package com.alex.wechat.mp.account.service.impl;

import java.io.Serializable;
import java.util.List;
import java.util.UUID;

import org.apache.commons.lang3.StringUtils;
import org.jeecgframework.core.common.model.json.AjaxJson;
import org.jeecgframework.core.common.model.json.LogAnnotation;
import org.jeecgframework.core.common.service.impl.CommonServiceImpl;
import org.jeecgframework.core.util.ResourceUtil;
import org.jeecgframework.core.util.oConvertUtils;
import org.jeecgframework.web.system.pojo.base.TSUser;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.alex.wechat.mp.account.entity.WxAccountEntity;
import com.alex.wechat.mp.account.service.WxAccountServiceI;
import com.alex.wechat.mp.accountmgr.entity.WxAccountMgrEntity;
import com.alex.wechat.mp.accountmgr.service.WxAccountMgrServiceI;
import com.alex.wechat.mp.config.WxContext;
import com.alex.wechat.mp.fans.entity.WxFansEntity;
import com.gomore.jeecg.common.Assert;
import com.gomore.jeecg.common.ServiceException;

import me.chanjar.weixin.mp.api.WxMpInMemoryConfigStorage;
import me.chanjar.weixin.mp.api.WxMpService;
import me.chanjar.weixin.mp.api.impl.WxMpServiceImpl;

@Service("wxAccountService")
@Transactional
public class WxAccountServiceImpl extends CommonServiceImpl implements WxAccountServiceI {

  @Autowired
  private WxMpService wxMpService;
  @Autowired
  private WxAccountMgrServiceI accountMgrService;

  @Override
  public <T> void delete(T entity) {
    super.delete(entity);
    // 执行删除操作配置的sql增强
    this.doDelSql((WxAccountEntity) entity);
  }

  @Override
  public <T> Serializable save(T entity) {
    Serializable t = super.save(entity);
    // 执行新增操作配置的sql增强
    this.doAddSql((WxAccountEntity) entity);
    return t;
  }

  @Override
  public <T> void saveOrUpdate(T entity) {
    super.saveOrUpdate(entity);
    // 执行更新操作配置的sql增强
    this.doUpdateSql((WxAccountEntity) entity);
  }

  /**
   * 默认按钮-sql增强-新增操作
   * 
   * @param id
   * @return
   */
  public boolean doAddSql(WxAccountEntity t) {
    // 保存管理者。
    TSUser curUser = ResourceUtil.getSessionUserName();
    WxAccountMgrEntity accountMgr = new WxAccountMgrEntity();
    accountMgr.setAccountId(t.getId());
    accountMgr.setUserId(curUser.getId());
    accountMgr.setUserName(curUser.getUserName());
    accountMgr.setRealName(curUser.getRealName());
    accountMgr.setActive(!WxContext.hasWxAccount());
    try {
      accountMgrService.save(accountMgr);
    } catch (Exception e) {
      throw new RuntimeException(e);
    }

    if (accountMgr.getActive()) {
      t = get(WxAccountEntity.class, t.getId());
      WxContext.setOriginalId(t.getOriginalId());
    }
    return true;
  }

  /**
   * 默认按钮-sql增强-更新操作
   * 
   * @param id
   * @return
   */
  public boolean doUpdateSql(WxAccountEntity t) {
    return true;
  }

  /**
   * 默认按钮-sql增强-删除操作
   * 
   * @param id
   * @return
   */
  public boolean doDelSql(WxAccountEntity t) {
    try {
      accountMgrService.deleteByWxAccountId(t.getId());
    } catch (Exception e) {
      throw new RuntimeException(e);
    }
    return true;
  }

  public String getAccessToken() {
    try {
      return wxMpService.getAccessToken();
    } catch (Exception e) {
      return null;
    }
  }

  public WxAccountEntity getWxAccountByLogin() {
    final String userId = ResourceUtil.getSessionUserId();

    if (StringUtils.isBlank(userId)) {
      // 如果没有登录，则取默认的一个
      WxAccountEntity account = getSingleWxAccount();
      if (account != null) {
        return account;
      }
    } else {
      final List<WxAccountMgrEntity> mgrs = findAccountMgrs(userId);
      if (mgrs.isEmpty()) {
        // 当前用户没有关联公众号，则取唯一的那个公众号
        WxAccountEntity account = getSingleWxAccount();
        if (account != null) {
          return account;
        }
      } else {
        String accoundId = null;

        if (mgrs.size() == 1) {
          accoundId = mgrs.get(0).getAccountId();
        } else if (mgrs.size() > 1) {
          // 默认取第一个
          accoundId = mgrs.get(0).getAccountId();

          // 如果有默认的，则取默认的公众号
          for (WxAccountMgrEntity mgr : mgrs) {
            if (mgr.getActive() != null && mgr.getActive()) {
              accoundId = mgr.getAccountId();
              break;
            }
          }
        }

        if (StringUtils.isNoneBlank(accoundId)) {
          return get(WxAccountEntity.class, accoundId);
        }
      }
    }

    return null;
  }

  /**
   * 取唯一的一个公众号
   * 
   * @return
   */
  private WxAccountEntity getSingleWxAccount() {
    List<WxAccountEntity> results = loadAll(WxAccountEntity.class);
    if (results.size() == 1) {
      return results.get(0);
    } else {
      return null;
    }
  }

  private List<WxAccountMgrEntity> findAccountMgrs(String userId) {
    Assert.assertArgumentNotEmpty(userId, "userId");
    return findByProperty(WxAccountMgrEntity.class, "userId", userId);
  }

  /**
   * 替换sql中的变量
   * 
   * @param sql
   * @return
   */
  public String replaceVal(String sql, WxAccountEntity t) {
    sql = sql.replace("#{id}", String.valueOf(t.getId()));
    sql = sql.replace("#{name}", String.valueOf(t.getName()));
    sql = sql.replace("#{token}", String.valueOf(t.getToken()));
    sql = sql.replace("#{number}", String.valueOf(t.getNumber()));
    sql = sql.replace("#{originalId}", String.valueOf(t.getOriginalId()));
    sql = sql.replace("#{type}", String.valueOf(t.getType()));
    sql = sql.replace("#{email}", String.valueOf(t.getEmail()));
    sql = sql.replace("#{description}", String.valueOf(t.getDescription()));
    sql = sql.replace("#{appid}", String.valueOf(t.getAppid()));
    sql = sql.replace("#{appsecret}", String.valueOf(t.getAppsecret()));
    sql = sql.replace("#{accesstoken}", String.valueOf(t.getAccesstoken()));
    sql = sql.replace("#{componentAppId}", String.valueOf(t.getComponentAppId()));
    sql = sql.replace("#{UUID}", UUID.randomUUID().toString());
    return sql;
  }

  /**
   * 通过微信原始ID，获取系统微信公众账号配置信息
   * 
   * @param originalId
   * @return
   */
  public WxAccountEntity getAccountByOriginalId(String originalId) {
    if (oConvertUtils.isEmpty(originalId)) {
      return null;
    }
    List<WxAccountEntity> results = this.findByProperty(WxAccountEntity.class, "originalId",
        originalId);
    if (results != null && results.size() > 0) {
      return results.get(0);
    } else {
      return null;
    }
  }

  @Override
  public WxAccountEntity getAccountByAppId(String appId) {
    Assert.assertArgumentNotEmpty(appId, "appid");

    List<WxAccountEntity> results = this.findByProperty(WxAccountEntity.class, "appid", appId);
    if (results != null && results.size() > 0) {
      return results.get(0);
    } else {
      return null;
    }
  }

  @Override
  public WxAccountEntity getAccountByOpenId(String openId) {
    Assert.assertArgumentNotEmpty(openId, "openId");

    String hql = "select o from " + WxAccountEntity.class.getName() + " o, "
        + WxFansEntity.class.getName() + " f where o.originalId = f.accountId and f.openid = ?";
    List<WxAccountEntity> results = this.findByHql(hql, openId);
    if (results != null && results.size() > 0) {
      return results.get(0);
    } else {
      return null;
    }
  }

  @Override
  public String getAccessToken(String accountId) {
    try {
      return getAccessToken(accountId, false);
    } catch (Exception e) {
      return null;
    }
  }

  /**
   * 重置 AccessToken
   * 
   * @return
   * @throws WexinReqException
   */
  @LogAnnotation(operateDescribe = "重置Token", operateFuncNm = "resetAccessToken",
      operateModelNm = "AjaxJson")
  @Override
  public AjaxJson resetAccessToken(String id) throws ServiceException {
    AjaxJson json = new AjaxJson();
    try {
      String accessToken = getAccessToken(id, true);
      json.setSuccess(true);
      json.setObj(accessToken);
    } catch (Exception e) {
      json.setSuccess(false);
      json.setMsg(e.getMessage());
    }
    return json;
  }

  @Override
  public void active(String id) throws ServiceException {
    WxAccountEntity account = get(WxAccountEntity.class, id);
    if (account == null) {
      throw new ServiceException("公众号不存在");
    }

    TSUser user = ResourceUtil.getSessionUserName();
    if (user == null) {
      throw new ServiceException("用户未登录");
    }

    executeHql("update " + WxAccountMgrEntity.class.getName() + " set active = ? where userId = ?",
        Boolean.FALSE, user.getId());
    executeHql(
        "update " + WxAccountMgrEntity.class.getName()
            + " set active = ? where userId = ? and accountId = ?",
        Boolean.TRUE, user.getId(), account.getId());

    // 设置当前公众号
    WxContext.setOriginalId(account.getOriginalId());
  }

  private String getAccessToken(String id, boolean forceRefresh) throws Exception {
    WxAccountEntity account = get(WxAccountEntity.class, id);
    if (account == null) {
      throw new ServiceException("公众号不存在");
    }

    WxMpInMemoryConfigStorage config = new WxMpInMemoryConfigStorage();
    config.setAppId(account.getAppid());
    config.setSecret(account.getAppsecret());
    config.setToken(account.getToken());
    config.setAesKey(account.getAesKey());
    WxMpService service = new WxMpServiceImpl();
    service.setWxMpConfigStorage(config);

    // 保存微信账户
    String accessToken = service.getAccessToken(true);
    account.setAccesstoken(accessToken);
    account.setExpiresTime(config.getExpiresTime());
    this.saveOrUpdate(account);

    return accessToken;
  }

}